use axum::{extract::Path, http::HeaderMap, routing::{get, put}, Json, Router };
use sea_orm::{query::*, DbBackend, FromQueryResult};

use crate::{auth::claims::get_id, code, query, sea_orm::{connect, send_sql_ok}};
use serde::{ Deserialize, Serialize };
#[derive(Debug, Deserialize, Serialize, FromQueryResult)]
pub struct Data {
    id: i32,
    label: String
}
pub async fn list(header:HeaderMap, table: &str, is_self:bool) -> Result<Json<JsonValue>, Json<JsonValue>>{
    let conn = connect().await?;
    let id = get_id(header)?;
    let stmt = Statement::from_string(
        DbBackend::MySql, 
        if is_self {
            format!("select id, label, id as value from {} where create_user={} order by id asc", table, id)
        }else{
            format!("select id, label, id as value from {} order by id asc", table)
        }
    );
    let result = Data::find_by_statement(stmt).into_json().all(&conn).await;
    code::send_arr(result)
}
pub async fn save(table: &str, header: HeaderMap, body:JsonValue) -> Result<Json<JsonValue>, Json<JsonValue>>{
    let conn = connect().await?;
    let label = query::str(&body, "label")?;
    let user = get_id(header)?;
    if let Some(f) = query::i32_op(&body, "id")? {
        let stmt = Statement::from_string(
            DbBackend::MySql, 
            format!("update {} set label='{}', update_user={} where id={}", table, label, user, f)
        );
        send_sql_ok(&conn,conn.execute(stmt).await).await
    }else{
        let stmt = Statement::from_string(
            DbBackend::MySql, 
            format!("insert into {} (label, create_user) values ('{}', {})", table, label, user)
        );
        send_sql_ok(&conn,conn.execute(stmt).await).await
    }
}
pub async fn find(table: &str, id:i32) -> Result<Json<JsonValue>, Json<JsonValue>>{
    let conn = connect().await?;
    let stmt = Statement::from_string(
        DbBackend::MySql, 
        format!("select id, label from {} where id={}", table, id)
    );
    let result = Data::find_by_statement(stmt).into_json().one(&conn).await;
    code::send_op_obj(result)
}
pub async fn del(table:&str, id:String) -> Result<Json<JsonValue>, Json<JsonValue>>{
    let conn = connect().await?;
    let ids = id.split(",").collect::<Vec<&str>>();
    let mut cid = "".to_string();
    for v in &ids{
        cid = cid + "'" + v + "'" + ","
    }
    let stmt = Statement::from_string(
        DbBackend::MySql, 
        format!("delete from {} where id in({})", table, cid.strip_suffix(",").unwrap())
    );
    code::send_ok(conn.execute(stmt).await)
}
pub async fn enabled(table: &str, header: HeaderMap, body:JsonValue) -> Result<Json<JsonValue>, Json<JsonValue>>{
    let conn = connect().await?;
    let enabled = query::i8(&body, "enabled")?;
    let user = get_id(header)?;
    if body["id"].is_array() {
        let id = query::vec_str(&body, "id")?;
        let mut cid = String::from("");
        for v in &id{
            cid = cid + "'" + v + "'" + ","
        }
        let stmt = Statement::from_string(
            DbBackend::MySql, 
            format!("update {} set enabled='{}', update_user={} where id in({})", table, enabled, user, cid.strip_suffix(",").unwrap())
        );
        send_sql_ok(&conn,conn.execute(stmt).await).await
    }else{
        let id = query::i32(&body, "id")?;
        let stmt = Statement::from_string(
            DbBackend::MySql, 
            format!("update {} set enabled='{}', update_user={} where id={}", table, enabled, user, id)
        );
        send_sql_ok(&conn,conn.execute(stmt).await).await
    }
}
pub fn route(table: &str, is_self:bool) -> Router{
    let a = table.to_owned();
    let b = table.to_owned();
    let c = table.to_owned();
    let d = table.to_owned();
    let e = table.to_owned();
    let f = table.to_owned();
    Router::new()
    .route(
        &format!("/{}", table),      
        get(move|header: HeaderMap| async move{ list(header,&a, is_self).await } )
        .post(move|header: HeaderMap, Json(body):Json<JsonValue>| async move{ save(&b, header, body).await } )
        .put(move|header: HeaderMap, Json(body):Json<JsonValue>| async move{ save(&c, header, body).await })
    )
    .route(
        &format!("/{}/{{id}}", table), 
        get(move|Path( id ): Path<String>| async move{
            if let Ok(f) = id.parse::<i32>(){
                find(&d, f).await
            }else{
                code::err("id 必须是数字")
            }
        })
        .delete(move|Path( id ): Path<String>| async move{ del(&e, id).await })
    )
    .route(
        &format!("/enabled/{}", table),      
        put(move|header: HeaderMap, Json(body):Json<JsonValue>| async move{  enabled(&f, header, body).await })
    )
}
// 只有查询操作，适用于固定数据
pub fn list_route(table: &str, is_self:bool) -> Router{
    let a = table.to_owned();
    Router::new()
    .route( &format!("/{}", table),get(move|header:HeaderMap| async move{ list(header,&a, is_self).await } ))
}